/* Includes ------------------------------------------------------------------*/
#include "ws2812b.h"
#include "beep.h"

/*----------------------------------------------------------------------------*/
/* Configure ws2812b                                                             */
/*----------------------------------------------------------------------------*/

extern uint8_t OPEN;

uint8_t lightness = 0xff;
uint8_t lightness_stay_buffer = 0;

uint8_t fade_delay = 0;
uint8_t max_fade_speed = 50;

uint8_t colorR = 0xff, colorG = 0xff, colorB = 0xff;
uint8_t colorR_Start = 0xff, colorG_Start = 0x00, colorB_Start = 0x00;
uint8_t colorR_End = 0x00, colorG_End = 0x00, colorB_End = 0xff;

uint8_t rBuffer[PIXEL_MAX] = {0x00};
uint8_t gBuffer[PIXEL_MAX] = {0x00};
uint8_t bBuffer[PIXEL_MAX] = {0x00};

uint32_t WS_Frame[24 * PIXEL_MAX];

void WS2812B_Init(void) {
  uint8_t i;
	uint8_t lightness_stay = lightness / 5;

  for (i = 0; i < PIXEL_MAX; i++) {
    rBuffer[i] = colorR_End;
    gBuffer[i] = colorG_End;
    bBuffer[i] = colorB_End;
  }
	for (i = 1; i <= lightness_stay; i++) {
    WS2812B_show(i);
		HAL_Delay(10);
  }
}

void WS2812B_Off(void) {
  uint8_t i;

  for (i = 0; i < PIXEL_MAX; i++) {
    rBuffer[i] = 0x00;
    gBuffer[i] = 0x00;
    bBuffer[i] = 0x00;
  }
  WS2812B_show(lightness);
}

void WS2812B_On(uint8_t r, uint8_t g, uint8_t b) {
  uint8_t i;

  for (i = 0; i < PIXEL_MAX; i++) {
    rBuffer[i] = r;
    gBuffer[i] = g;
    bBuffer[i] = b;
  }
  WS2812B_show(lightness);
}

void WS2812B_Blink(uint8_t delay) {
  uint8_t i;

  for (i = 0; i < 3; i++) {
    BEEP_Alarm(450);

    WS2812B_On(0xff, 0, 0);
    HAL_Delay(delay);
    WS2812B_Off();
    HAL_Delay(delay);
  }

  if (OPEN) {
    for (i = 0; i < PIXEL_MAX; i++) {
      rBuffer[i] = colorR;
      gBuffer[i] = colorG;
      bBuffer[i] = colorB;

      WS2812B_show(lightness);
    }
  } else {
    for (i = 0; i < PIXEL_MAX; i++) {
      rBuffer[i] = colorR_End;
      gBuffer[i] = colorG_End;
      bBuffer[i] = colorB_End;

      WS2812B_show(lightness_stay_buffer);
    }
    WS2812B_Update();
  }
}

void WS2812B_DeInit(uint8_t delay) {
  uint8_t i;

  for (i = 0; i < PIXEL_MAX; i++) {
    rBuffer[i] = colorR_End;
    gBuffer[i] = colorG_End;
    bBuffer[i] = colorB_End;

    WS2812B_show(lightness);
    HAL_Delay(delay);
  }

  lightness_stay_buffer = 0;
}

void WS2812B_Update() {
  uint8_t i, j;
  uint8_t lightness_stay = lightness / 5;
	
  if (lightness_stay_buffer == 0) {
		if (fade_delay == 0) {
			fade_delay = 10;
			WS2812B_show(lightness);
		} else {
			j = lightness - lightness_stay;

			for (i = 1; i <= j; i++) {
				WS2812B_show(lightness - i);
				HAL_Delay((fade_delay + i*i*2)<max_fade_speed ? (fade_delay + i*i*2):max_fade_speed);
			}
		}
    lightness_stay_buffer = lightness_stay;
  } else {
    if (lightness_stay_buffer > lightness_stay) {
      j = lightness_stay_buffer - lightness_stay;

      for (i = 0; i < j; i++) {
        WS2812B_show(lightness_stay_buffer - i);
        HAL_Delay((fade_delay + i*i*2)<max_fade_speed ? (fade_delay + i*i*2):max_fade_speed);
      }
    } else {
      j = lightness_stay - lightness_stay_buffer;

      for (i = 0; i < j; i++) {
        WS2812B_show(lightness_stay_buffer + i);
        HAL_Delay((fade_delay + i*i*2)<max_fade_speed ? (fade_delay + i*i*2):max_fade_speed);
      }
    }
    lightness_stay_buffer = lightness_stay;
  }
}

void WS2812B_flow(uint8_t delay) {
  uint8_t i;

  for (i = 0; i < PIXEL_MAX; i++) {
    rBuffer[i] = colorR_Start;
    gBuffer[i] = colorG_Start;
    bBuffer[i] = colorB_Start;
  }
	
	for (i = lightness_stay_buffer; i <= lightness; i++) {
    WS2812B_show(i);

		HAL_Delay((delay + (max_fade_speed - (i<max_fade_speed ? i:max_fade_speed))) / 2);
  }

  for (i = 0; i < PIXEL_MAX; i++) {
    rBuffer[i] = colorR;
    gBuffer[i] = colorG;
    bBuffer[i] = colorB;
    WS2812B_show(lightness);

    HAL_Delay(delay);
  }
}

void WS2812B_show(uint8_t lightness_show) {
  uint8_t i, j;

  for (i = 0; i < PIXEL_MAX; i++) {
    for (j = 0; j < 8; j++) {
      WS_Frame[24 * i + j] = ((uint8_t)(gBuffer[i] * lightness_show / 255.0) & (0x80 >> j)) ? BIT_1 : BIT_0;
      WS_Frame[24 * i + j + 8] = ((uint8_t)(rBuffer[i] * lightness_show / 255.0) & (0x80 >> j)) ? BIT_1 : BIT_0;
      WS_Frame[24 * i + j + 16] = ((uint8_t)(bBuffer[i] * lightness_show / 255.0) & (0x80 >> j)) ? BIT_1 : BIT_0;
    }
  }

  HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_3, WS_Frame, 2 * 24 * PIXEL_MAX);
}

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) {
  HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_3);
}
